package com.ap.core.bulkupload.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ap.core.bulkupload.service.BusinessRuleValidationService;
import com.ap.core.bulkupload.types.BulkFileUploadEnum;
import com.ap.core.bulkupload.validation.info.ValidationInfo;
import com.ap.core.bulkupload.validation.info.ValidationResult;
import com.ap.core.exception.APCoreException;
import com.ap.core.validation.rules.ValidationRule;

/**
 * User: Gibu.Paul
 * 
 * Implementation class for {@link BusinessRuleValidationService}
 */
public class DefaultBusinessRuleValidationServiceImpl implements BusinessRuleValidationService<Object> {
	
	private static final Logger LOG = LoggerFactory
			.getLogger(DefaultBusinessRuleValidationServiceImpl.class);

	private final Map<BulkFileUploadEnum, List<ValidationRule<Object>>> ruleMap;

	/** Whether rule validation should stop if any rule fails. */
	private final boolean failFast;

	/**
	 * 
	 * @param ruleMap
	 * @param failFast
	 */
	public DefaultBusinessRuleValidationServiceImpl(
			Map<BulkFileUploadEnum, List<ValidationRule<Object>>> ruleMap,
			boolean failFast) {
		this.ruleMap = ruleMap;
		this.failFast = failFast;
	}

	/**
	 * Validate the business rule
	 */
	@Override
	public ValidationResult validate(Object object,	BulkFileUploadEnum bulkValidationType) 
			throws APCoreException {
		// executes rules on the domain object and returns list of failures
		boolean passed = true;
		try {
			// get rule list to be applied to the object.
			final List<ValidationRule<Object>> rules = ruleMap
					.get(bulkValidationType);
			
			final List<ValidationInfo> failedRuInfo = new ArrayList<ValidationInfo>();
			if (null != rules) {
	
				for (ValidationRule<Object> rule : rules) {
	
					// call business rule here
					passed = rule.validate(object);
	
					if (!passed) {
						LOG.info("Failed business rule " + rule.getErrorCode()
								+ " at time : " + new LocalDateTime());
						failedRuInfo.add(new ValidationInfo(rule.getErrorCode()));
						/*failedRuInfo.add(new ValidationInfo(rule.getRuleId(), rule
								.getErrorCode(), rule.getRuleDescription()));*/
					}
	
					// * If fail fast is set return immediately on encountering an
					// error
	
					if ((failFast && !passed)) {
						break;
					}
				}
			}
			return new ValidationResult(failedRuInfo);
		}
		catch (Exception ex) {
			LOG.error("Exception occurred :["+Arrays.toString(ex.getStackTrace())+"]");
			throw new APCoreException(ex);
		}
	}
}
